package com.nowcoder.topic.dp.hard;

/**
 * NC196 编辑距离(一)
 * @author d3y1
 */
public class NC196{
    /**
     * 代码中的类名、方法名、参数名已经指定，请勿修改，直接返回方法规定的值即可
     *
     *
     * @param str1 string字符串
     * @param str2 string字符串
     * @return int整型
     */
    public int editDistance (String str1, String str2) {
        return solution1(str1, str2);
//        return solution2(str1, str2);
    }

    /**
     * 动态规划: 二维数组
     *
     * dp[i][j]表示使字符串str1的前i个字符与字符串str2的前j个字符相同所需要的最少操作数
     *
     *            { dp[i-1][j-1]                                                    , str1.charAt(i-1) == str2.charAt(j-1)
     * dp[i][j] = {
     *            { Math.min(dp[i-1][j-1]+1, Math.min(dp[i-1][j]+1, dp[i][j-1]+1))  , str1.charAt(i-1) != str2.charAt(j-1)
     *
     * @param str1
     * @param str2
     * @return
     */
    private int solution1(String str1, String str2){
        int n1 = str1.length();
        int n2 = str2.length();

        int[][] dp = new int[n1+1][n2+1];

        // init 删除
        for(int i=0; i<=n1; i++){
            dp[i][0] = i;
        }
        // init 新增
        for(int j=0; j<=n2; j++){
            dp[0][j] = j;
        }

        for(int i=1; i<=n1; i++){
            for(int j=1; j<=n2; j++){
                // 当前字符相同
                if(str1.charAt(i-1) == str2.charAt(j-1)){
                    dp[i][j] = dp[i-1][j-1];
                }
                // 当前字符不同
                else{
                    // str1 => str2
                    // 修改 dp[i-1][j-1]+1
                    // 删除 dp[i-1][j]+1
                    // 新增 dp[i][j-1]+1
                    dp[i][j] = Math.min(dp[i-1][j-1]+1, Math.min(dp[i-1][j]+1, dp[i][j-1]+1));
                }
            }
        }

        return dp[n1][n2];
    }

    /**
     * 动态规划: 一维数组(空间压缩)
     *
     * dp[j]表示编辑成字符串str2的前j个字符所需要的最少操作数
     *
     *         { pre                                            , str1.charAt(i-1) == str2.charAt(j-1)
     * dp[j] = {
     *         { Math.min(pre+1, Math.min(dp[j]+1, dp[j-1]+1))  , str1.charAt(i-1) != str2.charAt(j-1)
     *
     * @param str1
     * @param str2
     * @return
     */
    private int solution2(String str1, String str2){
        int n1 = str1.length();
        int n2 = str2.length();

        int[] dp = new int[n2+1];

        // init 新增
        for(int j=0; j<=n2; j++){
            dp[j] = j;
        }

        for(int i=1; i<=n1; i++){
            int pre = dp[0];
            // 重要
            dp[0] = i;
            for(int j=1; j<=n2; j++){
                int tmp = dp[j];

                // 当前字符相同
                if(str1.charAt(i-1) == str2.charAt(j-1)){
                    dp[j] = pre;
                }
                // 当前字符不同
                else{
                    // str1 => str2
                    // 修改 dp[i-1][j-1]+1 -> pre+1
                    // 删除 dp[i-1][j]+1   -> dp[j]+1
                    // 新增 dp[i][j-1]+1   -> dp[j-1]+1
                    dp[j] = Math.min(pre+1, Math.min(dp[j]+1, dp[j-1]+1));
                }
                pre = tmp;
            }
        }

        return dp[n2];
    }
}